package kuang.juc.single;


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

//懒汉式单例模式
public class LazyMan {
    //可以解决两次都是反射创建
    private static Boolean flag=true;       //妄想两次反射破坏

    private LazyMan(){
        synchronized (LazyMan.class){
            //可以解决第一次正常获取，第二次反射获取
            //if (lazyMan!=null){
            //    throw new  RuntimeException("妄想反射破坏");  //Caused by: java.lang.RuntimeException: 妄想反射破坏
            //}
            if (flag==true){
                flag=false;
            }else {
                throw new RuntimeException("妄想两次反射破坏");
            }
        }
        //看实例化次数
        //System.out.println(Thread.currentThread().getName()+"OK");
    }

    private volatile static LazyMan lazyMan;

    //DLC懒汉式
    public static LazyMan getInstance(){
        //双重检查锁定
        if (lazyMan==null){
            synchronized (LazyMan.class){
                if (lazyMan==null){
                    lazyMan=new LazyMan();  //不是一个原子操作
                    /**
                     * 1 分配内存空间
                     * 2 执行构造方法。，初始化对象
                     * 3 把这个对象指向这个空间
                     *
                     * 可能会出现指令重排
                     * 为了防止指令重排，lazyMan必须加volatile禁止指令重排
                     */
                }
            }
        }
        return lazyMan;
    }

    //反射破解单例模式
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //LazyMan instance1 = LazyMan.getInstance();
        //获取空参构造器
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        //假设破解了字段
        Field flag = LazyMan.class.getDeclaredField("flag");
        //破坏私有可见性
        flag.setAccessible(true);
        //忽视私有方法
        declaredConstructor.setAccessible(true);
        LazyMan instance1 = declaredConstructor.newInstance();
        //改回true
        flag.set(instance1,true);
        //又破坏
        //kuang.juc.single.LazyMan@1cd072a9
        //kuang.juc.single.LazyMan@7c75222b

        LazyMan instance2 = declaredConstructor.newInstance();
        System.out.println(instance1);  //正常kuang.juc.single.LazyMan@566776ad //反射kuang.juc.single.LazyMan@1b0375b3
        System.out.println(instance2);  //反射kuang.juc.single.LazyMan@6108b2d7 //反射kuang.juc.single.LazyMan@2f7c7260

    }

    //多线程并发
    //public static void main(String[] args) {
    //    for (int i = 0; i < 1000; i++) {
    //        new Thread(()->{
    //            LazyMan.getInstance();
    //        }).start();
    //    }
    //}
}
